package bobcorn.twilightopia.world.gen.feature;

import com.mojang.datafixers.Dynamic;

import bobcorn.twilightopia.blocks.ModBlocks;
import bobcorn.twilightopia.blocks.ProphetLogBlock;
import bobcorn.twilightopia.blocks.TwilightopiaSoilHelper;

import java.util.Random;
import java.util.Set;
import java.util.function.Function;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MutableBoundingBox;
import net.minecraft.world.gen.IWorldGenerationReader;
import net.minecraft.world.gen.feature.AbstractTreeFeature;
import net.minecraft.world.gen.feature.NoFeatureConfig;

public class ProphetTreeFeature extends AbstractTreeFeature<NoFeatureConfig> {
   private static final BlockState LOG = Blocks.BIRCH_LOG.getDefaultState();
   private static final BlockState EYE_LOG = ModBlocks.PROPHET_LOG.getDefaultState();
   private static final BlockState LEAF = Blocks.BIRCH_LEAVES.getDefaultState();
   private static final BlockState BELL_LEAF = ModBlocks.BELL_LEAVES.getDefaultState();
   private final boolean useExtraRandomHeight;

   public ProphetTreeFeature(Function<Dynamic<?>, ? extends NoFeatureConfig> configIn, boolean doBlockNotifyIn, boolean extraRandomHeightIn) {
      super(configIn, doBlockNotifyIn);
      this.useExtraRandomHeight = extraRandomHeightIn;
      this.setSapling((net.minecraftforge.common.IPlantable) ModBlocks.PROPHET_SAPLING);
   }

   public boolean place(Set<BlockPos> changedBlocks, IWorldGenerationReader worldIn, Random rand, BlockPos position, MutableBoundingBox p_208519_5_) {
	   int EyeYPos = rand.nextInt(3) + 1;
      int i = rand.nextInt(3) + 5;
      if (this.useExtraRandomHeight) {
         i += rand.nextInt(7);
      }

      boolean flag = true;
      if (position.getY() >= 1 && position.getY() + i + 1 <= worldIn.getMaxHeight()) {
         for(int j = position.getY(); j <= position.getY() + 1 + i; ++j) {
            int k = 1;
            if (j == position.getY()) {
               k = 0;
            }

            if (j >= position.getY() + 1 + i - 2) {
               k = 2;
            }

            BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos();

            for(int l = position.getX() - k; l <= position.getX() + k && flag; ++l) {
               for(int i1 = position.getZ() - k; i1 <= position.getZ() + k && flag; ++i1) {
                  if (j >= 0 && j < worldIn.getMaxHeight()) {
                     if (!func_214587_a(worldIn, blockpos$mutableblockpos.setPos(l, j, i1))) {
                        flag = false;
                     }
                  } else {
                     flag = false;
                  }
               }
            }
         }

         if (!flag) {
            return false;
         } else if ((TwilightopiaSoilHelper.isSoilOrChoco(worldIn, position.down())) && position.getY() < worldIn.getMaxHeight() - i - 1) {
        	 TwilightopiaSoilHelper.RemoveGrassAt(worldIn, position.down());

            for(int l1 = position.getY() - 3 + i; l1 <= position.getY() + i; ++l1) {
               int j2 = l1 - (position.getY() + i);
               int k2 = 1 - j2 / 2;

               for(int l2 = position.getX() - k2; l2 <= position.getX() + k2; ++l2) {
                  int i3 = l2 - position.getX();

                  for(int j1 = position.getZ() - k2; j1 <= position.getZ() + k2; ++j1) {
                     int k1 = j1 - position.getZ();
                     if (Math.abs(i3) != k2 || Math.abs(k1) != k2 || rand.nextInt(2) != 0 && j2 != 0) {
                        BlockPos blockpos = new BlockPos(l2, l1, j1);
                        if (isAirOrLeaves(worldIn, blockpos)) {
                        	int chance = rand.nextInt(4);
                        	this.setLogState(changedBlocks, worldIn, blockpos, chance != 0 ? LEAF : BELL_LEAF, p_208519_5_);
                        }
                     }
                  }
               }
            }

            for(int i2 = 0; i2 < i; ++i2) {
               if (isAirOrLeaves(worldIn, position.up(i2))) {
            	   if (i2 != EyeYPos)
            		   this.setLogState(changedBlocks, worldIn, position.up(i2), LOG, p_208519_5_);
            	   else {
            		   int dir = rand.nextInt(4);
            		   switch(dir) {
            		   		case 0:
            		   			this.setLogState(changedBlocks, worldIn, position.up(i2), EYE_LOG.with(ProphetLogBlock.FACING, Direction.EAST), p_208519_5_);
            		   			break;
            		   		case 1:
            		   			this.setLogState(changedBlocks, worldIn, position.up(i2), EYE_LOG.with(ProphetLogBlock.FACING, Direction.WEST), p_208519_5_);
            		   			break;
            		   		case 2:
            		   			this.setLogState(changedBlocks, worldIn, position.up(i2), EYE_LOG.with(ProphetLogBlock.FACING, Direction.NORTH), p_208519_5_);
            		   			break;
            		   		case 3:
            		   			this.setLogState(changedBlocks, worldIn, position.up(i2), EYE_LOG.with(ProphetLogBlock.FACING, Direction.SOUTH), p_208519_5_);
            		   			break;
            		   }
            		   
            	   }
               }
            }
            return true;
         } else {
            return false;
         }
      } else {
         return false;
      }
   }
}